using System;
using System.Web.Mvc;
using System.Web.Routing;
using Coderoom.ScrumPlanner.Domain;
using Coderoom.ScrumPlanner.Resources;
using Coderoom.ScrumPlanner.Tests.Integration.Internal;
using Coderoom.ScrumPlanner.Web;
using Coderoom.ScrumPlanner.Web.Controllers;
using Xunit;

namespace Coderoom.ScrumPlanner.Tests.Integration.ControllerTests
{
	public class ProjectControllerTests
	{
		private readonly ProjectController controller;

		public ProjectControllerTests()
		{
			XmlRepositoryTestHelper.ResetProjectDataFile();
			new MvcApplication().Application_Start();

			RouteTable.Routes.Clear();
			var factory = new StructureMapControllerFactory();
			controller = factory.CreateController<ProjectController>();
		}

		[Fact]
		public void List_returns_ViewResult_with_ProjectCollection()
		{
			// act
			var result = controller.List();

			// assert
			Assert.NotNull(result);
			Assert.IsType<ViewResult>(result);

			var model = ((ViewResult)result).ViewData.Model as ProjectCollection;
			Assert.NotNull(model);
			Assert.IsType<ProjectCollection>(model);
			Assert.Equal(3, model.Count);

			Assert.Equal(new Guid("CF4F74C1-CE66-4B06-8480-B34445906423"), model[0].Id);
			Assert.Equal("Project A", model[0].Title);
			Assert.Equal("project-a", model[0].Slug);

			Assert.Equal(new Guid("D8185A6C-7145-4751-B149-27B03AB9E5B6"), model[1].Id);
			Assert.Equal("Project B", model[1].Title);
			Assert.Equal("project-b", model[1].Slug);

			Assert.Equal(new Guid("7E97578E-214E-4792-8B41-5D378E59AB2B"), model[2].Id);
			Assert.Equal("Project X", model[2].Title);
			Assert.Equal("project-x", model[2].Slug);
		}

		[Fact]
		public void New_returns_ViewResult()
		{
			// act
			var result = controller.New();

			// assert
			Assert.NotNull(result);
			Assert.IsType<ViewResult>(result);
			Assert.Equal("New", ((ViewResult)result).ViewName);
		}

		[Fact]
		public void New2_returns_RedirectToRouteResult_when_a_project_is_created()
		{
			// arrange
			var projects = controller.ProjectService.GetProjects();
			Assert.Equal(3, projects.Count);

			// act
			var result = controller.New("New Project 1", "new-project-1");

			// assert
			Assert.NotNull(result);
			Assert.IsType<RedirectToRouteResult>(result);
			Assert.Equal("Detail", ((RedirectToRouteResult)result).RouteValues["action"]);
			Assert.Equal("new-project-1", ((RedirectToRouteResult)result).RouteValues["slug"]);

			projects = controller.ProjectService.GetProjects();
			Assert.Equal(4, projects.Count);

			Assert.NotEqual(Guid.Empty, projects[3].Id);
			Assert.Equal("New Project 1", projects[3].Title);
			Assert.Equal("new-project-1", projects[3].Slug);
		}

		[Fact]
		public void New2_returns_ViewResult_with_ModelStateErrors_when_input_validation_fails()
		{
			// arrange
			var projects = controller.ProjectService.GetProjects();
			Assert.Equal(3, projects.Count);

			// act
			var result = controller.New("", "");

			// assert
			Assert.NotNull(result);
			Assert.IsType<ViewResult>(result);
			Assert.Equal("New", ((ViewResult)result).ViewName);

			var validationErrors = ((ViewResult)result).ViewData.ModelState;
			Assert.NotNull(validationErrors);
			Assert.Equal(2, validationErrors.Count);
			Assert.Equal(ValidationMessages.Entity_TitleNotSpecified, validationErrors["title"].Errors[0].ErrorMessage);
			Assert.Equal(ValidationMessages.Entity_SlugNotSpecified, validationErrors["slug"].Errors[0].ErrorMessage);

			projects = controller.ProjectService.GetProjects();
			Assert.Equal(3, projects.Count);
		}

		[Fact]
		public void New2_returns_ViewResult_with_ModelStateErrors_when_slug_is_not_unique()
		{
			// arrange
			var projects = controller.ProjectService.GetProjects();
			Assert.Equal(3, projects.Count);
			var existingSlug = projects[1].Slug;

			// act
			var result = controller.New("", existingSlug);

			// assert
			Assert.NotNull(result);
			Assert.IsType<ViewResult>(result);
			Assert.Equal("New", ((ViewResult)result).ViewName);

			var validationErrors = ((ViewResult)result).ViewData.ModelState;
			Assert.NotNull(validationErrors);
			Assert.Equal(2, validationErrors.Count);
			Assert.Equal(ValidationMessages.Entity_TitleNotSpecified, validationErrors["title"].Errors[0].ErrorMessage);
			Assert.Equal(ValidationMessages.Entity_SlugInUse, validationErrors["slug"].Errors[0].ErrorMessage);

			projects = controller.ProjectService.GetProjects();
			Assert.Equal(3, projects.Count);
		}

		[Fact]
		public void Detail_returns_ViewResult_with_Project_when_project_is_found()
		{
			// act
			var result = controller.Detail("project-b");

			// assert
			Assert.NotNull(result);
			Assert.IsType<ViewResult>(result);

			var model = ((ViewResult)result).ViewData.Model as Project;
			Assert.NotNull(model);
			Assert.IsType<Project>(model);

			Assert.Equal(new Guid("D8185A6C-7145-4751-B149-27B03AB9E5B6"), model.Id);
			Assert.Equal("Project B", model.Title);
			Assert.Equal("project-b", model.Slug);
		}

		[Fact]
		public void Detail_returns_ViewResult_with_ModelStateErrors_when_project_is_not_found()
		{
			// act
			var result = controller.Detail("project-b");

			// assert
			Assert.NotNull(result);
			Assert.IsType<ViewResult>(result);
			Assert.Equal("Detail", ((ViewResult)result).ViewName);

			var validationErrors = ((ViewResult)result).ViewData.ModelState;
			Assert.NotNull(validationErrors);
			Assert.Equal(1, validationErrors.Count);
			Assert.Equal(ProjectControllerMessages.Project_NotFound, validationErrors["project"].Errors[0].ErrorMessage);
		}
	}
}